<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch, watchEffect } from 'vue'
import { throttle } from 'lodash'
import moment from 'moment'
import { usePlaybackStore } from '@/store/gps/playback'
import { storeToRefs } from 'pinia'

const playbackStore = usePlaybackStore()

const props = defineProps({
  playbackTimeLine: {
    type: Object,
    required: true,
    default: [] as any[]
  },
  playbackStopTimeLine: {
    type: Object,
    required: true,
    default: [] as any[]
  }
})

const curPlayingTs = defineModel<number>()
const emits = defineEmits(['controlVideo'])
const { newlineTime, playbackList, newPlayingIndex } = storeToRefs(playbackStore)

const getPixelRatio = function (context) {
  const backingStore =
    context.backingStorePixelRatio ||
    context.webkitBackingStorePixelRatio ||
    context.mozBackingStorePixelRatio ||
    context.msBackingStorePixelRatio ||
    context.oBackingStorePixelRatio ||
    context.backingStorePixelRatio ||
    1
  return (window.devicePixelRatio || 1) / backingStore
}
const ratio = getPixelRatio(window)

const canvasRef = ref<any>(null)
const containerRef = ref<any>(null)
const ctxRef = ref<any>(null)
// 可选的每个间隔代表多少分钟
const minutePerStep = ref([1, 2, 5, 10, 15, 20, 30, 60, 120, 180, 240, 360, 720, 1440])
// 最小刻度间距
const minScaleSpacing = ref(10)
// 整个时间轴表示的时间长度
let totalRulerHours = 24
// 允许的最小大格长度px值 如果调小 大格会变密集
const minLargeScaleSpacing = ref(100)
// 缩放层级
let zoom = 24
const currentTime = ref(new Date().getTime() / 1000)
const isMove = ref(false)
// 游标颜色
const drawCursorColor = '#3B5EFF'
// 刻度处背景颜色
const fillScaleBgColor = '#ffffff'
// 刻度颜色
const drawScaleColor = '#606266'
// 鼠标悬浮移动 游标颜色
const hoverMoveColor = '#fd7484'
// 录像时间块颜色
const fillTimePartsColor = 'rgba(30,95,223,0.5)'
const fillStopPartsColor = 'rgba(59,255,128)'
let moveTimer: any = null
let startTimestamp = 0
// 鼠标是否被按下 用来确认时hover事件还是拖拽事件
let isMouseDownFlag = false
// 是否拖拽 用来确认mouseup时是点击事件还是拖拽事件
let isDragFlag = false
// 鼠标按下时鼠标x位置 在处理拖拽事件中用来比对
const mousedownX = ref(0)

watch(
  () => props.playbackTimeLine,
  () => {
    let len = props.playbackTimeLine?.length
    if (len) {
      let first = props.playbackTimeLine?.[0]
      let last = props.playbackTimeLine?.[len - 1]
      currentTime.value = (parseInt(last.end) + parseInt(first.start)) / 2
    }
    init()
  }
)
watch(curPlayingTs, () => {
  init()
})
const refreshStartTimestamp = () => {
  // 开始时间 = 中间时间 - 一半得整条时间
  // 当currentTime改变或者整条时间轴代表的totalHours改变的时候 就刷新左边开始时间
  startTimestamp = currentTime.value - (totalRulerHours * 60 * 60) / 2
}

const clearcanvas = () => {
  if (!ctxRef.value || !canvasRef.value) {
    return
  }
  ctxRef.value.clearRect(0, 0, canvasRef.value.width || 0, canvasRef.value.height || 0)
}

const fillScaleBg = () => {
  if (ctxRef.value) {
    ctxRef.value.fillStyle = fillScaleBgColor
    ctxRef.value.fillRect(0, 0, canvasRef.value?.width || 0, 50)
  }
}

const createScaleText = (time) => {
  if (time.getHours() === 0 && time.getMinutes() === 0 && time.getMilliseconds() === 0) {
    return moment(time).format('YYYY-MM-DD')
  }
  return moment(time).format('HH:mm')
}

const drawScale = () => {
  if (!canvasRef.value || !ctxRef.value) {
    return
  }
  // 一分钟多少像素
  let oneMinutePx = canvasRef.value.width / (totalRulerHours * 60)
  // 一秒多少像素
  let oneMSPx = oneMinutePx / 60
  // 刻度间隔 默认20px
  let scaleSpacing = minScaleSpacing.value
  // 每格代表多少分钟
  let scaleUnit = scaleSpacing / oneMinutePx
  let len = minutePerStep.value.length
  for (let i = 0; i < len; i += 1) {
    if (scaleUnit < minutePerStep.value[i]) {
      // 选择正确的刻度单位分钟
      scaleUnit = minutePerStep.value[i]
      // 每刻度之间的距离 = 一分钟多少像素 * 刻度单位
      // 即 scaleUnit = scaleSpacing / oneMinutePx 的变形
      // 主要是 totalRulerHours 会变化 需要根据这个的变化来计算...
      scaleSpacing = oneMinutePx * scaleUnit
      break
    }
  }

  // 有刻度文字的大格相当于多少分钟 相当于直尺上的1cm
  let mediumStep = 30
  for (let i = 0; i < len; i++) {
    if (minLargeScaleSpacing.value / oneMinutePx <= minutePerStep.value[i]) {
      mediumStep = minutePerStep.value[i]
      break
    }
  }

  let totalScales = canvasRef.value.width / scaleSpacing
  // 某个刻度距离最左端得距离
  let graduationLeft
  // 某个刻度得时间
  let graduationTime
  let lineHeight
  refreshStartTimestamp()
  // 因为中间点是currentTime.value是固定的 最右边不一定在某个刻度上 会有一定的偏移量
  let leftOffsetMs = scaleUnit * 60 - (startTimestamp % (scaleUnit * 60))
  // 开始时间偏移距离(px)
  let leftOffsetPx = leftOffsetMs * oneMSPx
  // 一刻度多少秒
  let oneScalesMS = scaleSpacing / oneMSPx
  // 文字颜色
  ctxRef.value.fillStyle = drawScaleColor
  ctxRef.value.font = '24px serif'

  // 刻度线颜色
  ctxRef.value.strokeStyle = drawScaleColor
  ctxRef.value.beginPath()
  // 画刻度线
  function drawScaleLine(left, height) {
    ctxRef.value.moveTo(left, 0)
    ctxRef.value.lineTo(left, height)
    ctxRef.value.lineWidth = 1
  }
  for (let i = 0; i < totalScales; i++) {
    // 距离 = 开始得偏移距离 + 格数 * 每格得px;
    graduationLeft = leftOffsetPx + i * scaleSpacing
    // 时间 = 左侧开始时间 + 偏移时间 + 格数 * 一格多少秒
    graduationTime = startTimestamp + leftOffsetMs + i * oneScalesMS
    let date = new Date(graduationTime * 1000)
    if ((graduationTime / 60) % mediumStep === 0) {
      // 大格刻度
      lineHeight = 80
      let scaleText = createScaleText(date)
      ctxRef.value.fillText(scaleText, graduationLeft - 30, 100)
    } else {
      // 小格刻度
      lineHeight = 60
    }
    drawScaleLine(graduationLeft, lineHeight)
  }
  ctxRef.value.stroke()
}

const fillTimeParts = (part: any) => {
  let onePxsMS = canvasRef.value.width / (totalRulerHours * 60 * 60)
  let beginX = (part.start - startTimestamp) * onePxsMS
  let partWidth = (part.end - part.start) * onePxsMS
  ctxRef.value.fillStyle = fillTimePartsColor
  ctxRef.value.fillRect(beginX, 0, partWidth, 70)
}
const fillStopParts = (part: any) => {
  let onePxsMS = canvasRef.value.width / (totalRulerHours * 60 * 60)
  let beginX = (part.start - startTimestamp) * onePxsMS
  let partWidth = (part.end - part.start) * onePxsMS
  ctxRef.value.fillStyle = fillStopPartsColor
  ctxRef.value.fillRect(beginX, 0, partWidth, 50)
}

const drawCursor = () => {
  if (!canvasRef.value || !ctxRef.value) {
    return
  }
  // ctxRef.value.beginPath()
  // ctxRef.value.moveTo(canvasRef.value.width / 2 - 1, 0) //lineWidth 2 so need -1
  // ctxRef.value.lineTo(canvasRef.value.width / 2 - 1, 150)
  // ctxRef.value.strokeStyle = drawCursorColor
  // ctxRef.value.lineWidth = 2
  // ctxRef.value.stroke()
  // ctxRef.value.fillStyle = drawCursorColor
  // ctxRef.value.font = '18px serif'
  // ctxRef.value.fillText(formatTimeLine(currentTime.value), canvasRef.value.width / 2 - 100, canvasRef.value.height - 100)
}

const drawCurTs = () => {
  if (!canvasRef.value || !ctxRef.value) {
    return
  }
  let onePxsMS = canvasRef.value.getBoundingClientRect().width / (totalRulerHours * 60 * 60) // 每像素多少秒
  let posX = (curPlayingTs.value! / 1000 - startTimestamp) * onePxsMS

  ctxRef.value.beginPath()
  ctxRef.value.moveTo(posX * ratio - 1, 0)
  ctxRef.value.lineTo(posX * ratio - 1, 110)
  ctxRef.value.strokeStyle = drawCursorColor
  ctxRef.value.lineWidth = 1
  ctxRef.value.stroke()
  ctxRef.value.fillStyle = drawCursorColor
  ctxRef.value.fillText(formatTimeLine(curPlayingTs.value! / 1000), posX * ratio - 95, 130)
}

function formatTimeLine(val) {
  return moment(val * 1000).format('YYYY-MM-DD HH:mm:ss')
}

const init = () => {
  refreshStartTimestamp()
  clearcanvas() // 清空画布
  fillScaleBg() // 画刻度处背景
  drawScale() // 画刻度
  if (props.playbackTimeLine?.length) {
    props.playbackTimeLine.forEach((element: any) => {
      fillTimeParts(element)
    })
  }
  if (props.playbackStopTimeLine?.length) {
    props.playbackStopTimeLine.forEach((element: any) => {
      fillStopParts(element)
    })
  }
  drawCursor() // 画游标
  drawCurTs()
}

const setIsMove = (Move) => {
  if (isMove.value === Move) {
    return
  }
  isMove.value = Move
  const clearTimer = () => {
    if (moveTimer) {
      clearInterval(moveTimer)
      moveTimer = null
    }
  }
  if (isMove.value) {
    // 先清除之前得timer 否则会有两个timer通知进行...
    if (moveTimer) {
      clearTimer()
    }
    moveTimer = setInterval(() => {
      currentTime.value += 1000
      init()
    }, 1000)
  } else {
    clearTimer()
  }
}

const dragMove = (event) => {
  let posX = getMouseXRelativePos(event)
  let diffX = posX - mousedownX.value
  let onePxsMS = canvasRef.value.width / (totalRulerHours * 60 * 60)
  currentTime.value = currentTime.value - Math.round(diffX / onePxsMS)
  init()
  // 👇因为重新设置了currentTime 所以要重新设置鼠标按下位置
  // 否则偏移时间会进行累加 越拖越快越拖越快...
  mousedownX.value = posX
}

const hoverMove = (event) => {
  const posX = getMouseXRelativePos(event)
  const t = getMousePosTime(event)
  init()
  ctxRef.value.beginPath()
  ctxRef.value.moveTo(posX * ratio - 1, 0)
  ctxRef.value.lineTo(posX * ratio - 1, 120)
  ctxRef.value.strokeStyle = hoverMoveColor
  ctxRef.value.lineWidth = 3
  ctxRef.value.stroke()
  ctxRef.value.fillStyle = hoverMoveColor
  ctxRef.value.fillText(formatTimeLine(t), posX * ratio - 95, 150)
}

const eventListener = {
  wheel(event) {
    wheelEvent(event)
    hoverMove(event)
  },
  mousedown(event) {
    isMouseDownFlag = true
    mousedownX.value = getMouseXRelativePos(event)
  },
  mousemove(event) {
    if (isMouseDownFlag) {
      isDragFlag = true
      dragMove(event)
    } else {
      hoverMove(event)
    }
  },
  mouseup(event) {
    if (!isDragFlag) {
      hoverMove(event)
      timelineControlHisVideo(getMousePosTime(event))
    } else {
      // emits('controlVideo', currentTime.value)
    }
    // 初始化这俩值以免影响下次事件判断
    isMouseDownFlag = false
    isDragFlag = false
  },
  mouseleave(event) {
    init()
    // 初始化这俩值以免影响下次事件判断
    isMouseDownFlag = false
    isDragFlag = false
  }
}
function timelineControlHisVideo(t: number) {
  const time = moment(t * 1000)
  const index = playbackList.value.findIndex((item) => time.isBefore(item.endTimeMoment))
  if (index < 0) {
    return
  }
  newlineTime.value = time.valueOf()
  curPlayingTs.value = t * 1000
  newPlayingIndex.value = index
}

const getMousePosTime = (event) => {
  let posX = getMouseXRelativePos(event)
  let onePxsMS = canvasRef.value.getBoundingClientRect().width / (totalRulerHours * 60 * 60) // 每像素多少秒
  return startTimestamp + posX / onePxsMS
}
const wheelEvent = (event) => {
  event.preventDefault()
  // 是放大一倍还是缩小一倍
  let delta = Math.max(-1, Math.min(1, event.wheelDelta))
  if (delta < 0) {
    zoom = zoom + 2
    if (zoom >= 48) {
      //放大最大24小时
      zoom = 48
    }
    totalRulerHours = zoom
  } else if (delta > 0) {
    // 放大
    zoom = zoom - 2
    if (zoom <= 1) {
      //缩小最小1小时
      zoom = 1
    }
    totalRulerHours = zoom
  }
  init()
}
const getMouseXRelativePos = (event) => {
  let scrollX = document.documentElement.scrollLeft || document.body.scrollLeft
  let x = event.pageX || event.clientX + scrollX
  // canvasRef.value元素距离窗口左侧距离
  let baseLeft = canvasRef.value.getBoundingClientRect().x
  return x - baseLeft
}

const setCanvasWH = throttle(() => {
  if (canvasRef.value && containerRef.value) {
    canvasRef.value.width = containerRef.value.clientWidth * ratio
    canvasRef.value.height = containerRef.value.clientHeight * ratio
  }
  init()
}, 1000)

watchEffect(() => {
  // setIsMove(props.isMove1)
})

onMounted(() => {
  ctxRef.value = canvasRef.value.getContext('2d')
  init()
  setCanvasWH()
  window.addEventListener('resize', setCanvasWH)
  canvasRef.value.addEventListener('wheel', eventListener.wheel)
  canvasRef.value.addEventListener('mousedown', eventListener.mousedown)
  canvasRef.value.addEventListener('mousemove', eventListener.mousemove)
  canvasRef.value.addEventListener('mouseup', eventListener.mouseup)
  canvasRef.value.addEventListener('mouseleave', eventListener.mouseleave)
})

onUnmounted(() => {
  destroy()
})

const destroy = () => {
  window.removeEventListener('resize', setCanvasWH)
  if (canvasRef.value) {
    canvasRef.value.removeEventListener('wheel', eventListener.wheel)
    canvasRef.value.removeEventListener('mousedown', eventListener.mousedown)
    canvasRef.value.removeEventListener('mousemove', eventListener.mousemove)
    canvasRef.value.removeEventListener('mouseup', eventListener.mouseup)
    canvasRef.value.removeEventListener('mouseleave', eventListener.mouseleave)
    clearcanvas()
  }

  if (moveTimer) {
    clearInterval(moveTimer)
    moveTimer = null
  }
}
</script>

<template>
  <div ref="containerRef" class="time_line_container">
    <canvas ref="canvasRef" height="40" width="100" />
  </div>
</template>

<style scoped lang="scss">
.time_line_container {
  height: 100%;
  padding-top: 10px;
  overflow: hidden;
  canvas {
    width: 100%;
    height: 100%;
    background: #ffffff;
    font-size: 20px;
  }
}
</style>
